/**************************************************************************
 * @name: cond.c
 * @brief: 条件量和互斥锁代码练习一
 * @date: 2025/02/14
 * @author: boluzs@163.com
 * @note:
 * 练习:
 *      设计一个程序，程序中要求有3个线程，主线程创建2个子线程A和B，并创建1个互斥锁和2个条件量。
 *      要求子线程A作为生产者，生产数据并存放在数据缓冲区(可以定义一个全局变量，假设是一个字符数组，容量假设是10个字节)，每次随机生成1个范围在100内的数字并放入数组中，当数组已满的时候，则子线程A进入阻塞等待状态。
 *      要求子线程B作为消费者，从数据缓冲区读取数据，每次读取一个字节并输出到终端，当数组为空的时候，则子线程B进入阻塞等待状态。
 * @version: 1.0.0
 * @Copyright (c) 2025 by boluzs@163.com, All Rights Reserved.
 **************************************************************************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>

#include <time.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>

#define BUF_SIZE 10

char buf[BUF_SIZE] = {0};

int count = 0; // 作为计数器
int index1 = 0;
int index2 = 0;

// 定义两个条件量
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;

// 定义一个互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// 构造线程的回调函数 格式是固定的
void *threadA_handler(void *arg)
{
    srand(time(NULL)); // 初始化随机数种子
    for (;;)
    {
        // P操作
        pthread_mutex_lock(&mutex);

        // 判断条件:数组已满则阻塞
        while (count == BUF_SIZE)
        {
            printf("threadA is waiting...\n");
            pthread_cond_wait(&cond1, &mutex);
        }

        // 随机生成一个100以内的数字并放入数组内
        buf[index1] = rand() % 100;
        printf("write data from buf[%d] = %d\n", index1, buf[index1]);

        // 防止下标越界，所以当数组空间满了之后，应该从数组头部继续存储
        index1 = (index1 + 1) % BUF_SIZE;
        count++;

        // 通知线程B去数组中读取数据
        pthread_cond_signal(&cond2);

        // V操作
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
}

// 构造线程的回调函数 格式是固定的
void *threadB_handler(void *arg)
{
    int data = 0;
    for (;;)
    {
        // P操作
        pthread_mutex_lock(&mutex);

        // 判断条件：数组为空则阻塞
        while (count == 0)
        {
            printf("threadB is waiting...\n");
            pthread_cond_wait(&cond2, &mutex);
        }

        // 读取数组中的数据
        data = buf[index2];
        printf("read data from buf[%d] = %d\n", index2, data);
        index2 = (index2 + 1) % BUF_SIZE;
        count--;

        // 通知线程A写入数据
        pthread_cond_signal(&cond1);

        // V操作
        pthread_mutex_unlock(&mutex);
        sleep(10);
    }
}

int main()
{

    pthread_t newthreadA_id = 0; // 用于记录创建的新线程的ID，可以理解为是线程的句柄
    pthread_t newthreadB_id = 0; // 用于记录创建的新线程的ID，可以理解为是线程的句柄

    // 1.创建新线程
    pthread_create(&newthreadA_id, NULL, threadA_handler, NULL);
    pthread_create(&newthreadB_id, NULL, threadB_handler, NULL);

    // 2.
    pthread_join(newthreadA_id, NULL);
    pthread_join(newthreadB_id, NULL);

    // 主线程的任务
    for (;;)
    {
    }
    return 0;
}
